﻿using System;
using System.ComponentModel;
using System.Windows;
using System.Windows.Interop;
using _3DTicTacToe.Net;
using _3DTicTacToe.UI.Components;
using Microsoft.WindowsAPICodePack.Dialogs;
using TicTacToe.Core;

namespace _3DTicTacToe.UI
{
    partial class GameWindow : Window
    {
        readonly TicTacToeGame _game;
        readonly bool _isNetGame;

        // tool window handling

        bool _chatWindowOpened;
        bool _turnWindowOpened;

        NetChatWindow _chatWindow;
        TurnListWindow _turnWindow;

        //

        public GameWindow(TicTacToeGame game)
        {
            InitializeComponent();

            _game = game;
            SetupCommon();

            UpdateTitle(true);
        }

        public GameWindow(NetGame game)
        {
            InitializeComponent();

            _game = game;
            SetupCommon();

            _isNetGame = true;
            restartGameMenuItem.IsEnabled = false;
            startNewGameMenuItem.IsEnabled = false;
            toggleChatMenuItem.IsEnabled = true;

            // make sure player can only make turns when he is supposed to
            gameView2D.SetLock(game.NextPlayer != game.LocalPlayer);
            game.OnTurn += delegate { gameView2D.SetLock(game.NextPlayer != game.LocalPlayer); };

            game.OnChatMessageReceived += delegate(string message) { Action a = () => { if (!_chatWindowOpened) { ToggleChatWindow(null, null); _chatWindow.ChatMessageReceived(message); } }; Dispatcher.Invoke(a); };
            game.OnGameOver += delegate { game.Shutdown(); };
            //game.OnDisconnected += NetGame_Disconnected;

            // kill everything in case the window is closing
            Closing += delegate { if (!game.IsOver) game.Shutdown(); };

            //update title
            UpdateTitle(true);
        }

        GameWindow()
        {
            InitializeComponent();
        }

        void SetupCommon()
        { 
            gameView2D.OnPreviewUpdate += UpdatePreview;
            gameView2D.OnClearPreview += ClearPreview;
            gameView2D.OnNewTurn += NewTurn;
            _game.OnGameOver += OnGameOver;
            _game.OnTurn += Game_OnTurn;
            Closing += WindowClosing;

            playerPanel.UpdatePanel(_game.NextPlayer);
        }

        void UpdateTitle(bool firstRun)
        {
            if (_isNetGame)
            {
                this.Title = "3DTicTacToe - " + ((_game.NextPlayer == (_game as NetGame).LocalPlayer) ? "Your turn" : "Waiting for " + (_game as NetGame).RemotePlayer.Name + "'s turn");
                if (!firstRun) NativeMethods.Flash(Handle);
            }
            else
                this.Title = "3DTicTacToe - " + ((_game.NextPlayer == _game.PlayerOne) ? _game.PlayerOne.Name : _game.PlayerTwo.Name) + "'s turn";
        }

        IntPtr Handle
        {
            get
            {
                return (HwndSource.FromVisual(this) as HwndSource).Handle;
            }
        }

        #region Game Logic Event Handlers

        void OnGameOver(object sender, GameOverEventArgs e)
        {
            Action action = () =>
                {
                    gameView2D.SetLock(true);
                    gameMenu.IsEnabled = false;
                    playerPanel.UpdatePanelForGameOver(e.WinningPlayer);

                    var window = new GameOverWindow(e, _game, _isNetGame) { Owner = this, Topmost = true };
                    window.Show();
                };
            Dispatcher.Invoke(action); // will be called from non-ui thread, so invoke it safely
        }


        void NewTurn(object sender, NewTurnEventArgs e)
        {
            _game.MakeTurn(new Turn(_game.NextPlayer, e.X1, e.X2, e.X3));
        }

        void Game_OnTurn(object sender, TurnEventArgs e)
        {
            var point = e.Turn.GetPoint();
            var color = e.Turn.Player.Color;
            var isPlayerOne = e.Turn.Player == _game.PlayerOne;

            Action action = () =>
                {
                    gameView2D.UpdateGameView(point, color, isPlayerOne);
                    gameView3D.UpdateGameView(point, color, isPlayerOne);
                    playerPanel.UpdatePanel(_game.NextPlayer);

                    UpdateTitle(false);
                };
            Dispatcher.Invoke(action); // will be called from non-ui thread, so invoke it safely
        }

        void UpdatePreview(object sender, PreviewUpdateEventArgs e)
        {
            if (!_game.IsValidTurn(e.X1, e.X2, e.X3))
            {
                ClearPreview(null, null);
                return;
            }

            var point = e.GetPoint();
            var color = _game.NextPlayer.Color;
            var isPlayerOne = _game.PlayerOne == _game.NextPlayer;

            gameView2D.UpdatePreview(point, color, isPlayerOne);
            gameView3D.UpdatePreview(point, color, isPlayerOne);
        }

        void ClearPreview(object sender, EventArgs args)
        {
            gameView2D.ClearPreview();
            gameView3D.ClearPreview();
        }

        #endregion

        #region UI Event Handlers

        void ExitProgramItemHandler(object sender, RoutedEventArgs e)
        {
            bool exit = false;

            if (TaskDialog.IsPlatformSupported)
            {
                using (var dlg = new TaskDialog())
                {
                    dlg.Caption = "Exit 3DTicTacToe";
                    dlg.InstructionText = "Exit Program?";
                    dlg.Text = "All game progress wil be lost if you quit the program.";
                    dlg.OwnerWindowHandle = this.Handle;
                    dlg.StartupLocation = TaskDialogStartupLocation.CenterOwner;

                    var exitLink = new TaskDialogCommandLink("exit", "Exit");
                    var continuteLink = new TaskDialogCommandLink("continue", "Continue Playing", "Continue with current game.");

                    exitLink.Click += delegate
                    {
                        exit = true;
                        dlg.Close();
                    };
                    continuteLink.Click += delegate
                    {
                        dlg.Close();
                    };

                    dlg.Controls.Add(exitLink);
                    dlg.Controls.Add(continuteLink);

                    dlg.Show();
                }
            }
            else
            {
                var result = MessageBox.Show("Exit Program?", "Exit 3DTicTacToe", MessageBoxButton.YesNo, MessageBoxImage.Question);
                if (result == MessageBoxResult.Yes)
                    exit = true;
            }

            if (exit)
                App.Current.Shutdown();
        }

        void UndoTurnItemHandler(object sender, RoutedEventArgs e)
        {
            _game.UndoTurn();
        }

        void RestartGameItemHandler(object sender, RoutedEventArgs e)
        {
            bool restart = false;

            if (TaskDialog.IsPlatformSupported)
            {
                using (var dlg = new TaskDialog())
                {
                    dlg.Caption = "Restart Game";
                    dlg.InstructionText = "Restart Game?";
                    dlg.Text = "If you decide to restart the game, the current game progress is lost";
                    dlg.OwnerWindowHandle = this.Handle;
                    dlg.StartupLocation = TaskDialogStartupLocation.CenterOwner;

                    var restartLink = new TaskDialogCommandLink("restart", "Restart");
                    var continuteLink = new TaskDialogCommandLink("continue", "Continue", "Continue with current game.");

                    restartLink.Click += delegate
                    {
                        restart = true;
                        dlg.Close();
                    };
                    continuteLink.Click += delegate
                    {
                        dlg.Close();
                    };

                    dlg.Controls.Add(restartLink);
                    dlg.Controls.Add(continuteLink);

                    dlg.Show();
                }
            }
            else
            {
                var result = MessageBox.Show("Restart Game?", "Restart Game", MessageBoxButton.YesNo, MessageBoxImage.Question);
                if (result == MessageBoxResult.Yes)
                    restart = true;
            }

            if (restart)
            {
                var game = new TicTacToeGame(_game.PlayerOne, _game.PlayerTwo);
                new GameWindow(game).Show();
                Close();
            }
        }

        void StartNewGameItemHandler(object sender, RoutedEventArgs e)
        {
            bool startNew = false;

            if (TaskDialog.IsPlatformSupported)
            {
                using (var dlg = new TaskDialog())
                {
                    dlg.Caption = "Start New Game";
                    dlg.InstructionText = "Start New Game?";
                    dlg.Text = "If you decide to start a new game, the current game progress is lost";
                    dlg.OwnerWindowHandle = this.Handle;
                    dlg.StartupLocation = TaskDialogStartupLocation.CenterOwner;

                    var startNewLink = new TaskDialogCommandLink("startnew", "Start New");
                    var continuteLink = new TaskDialogCommandLink("continue", "Continue", "Continue with current game.");

                    startNewLink.Click += delegate
                    {
                        startNew = true;
                        dlg.Close();
                    };
                    continuteLink.Click += delegate
                    {
                        dlg.Close();
                    };

                    dlg.Controls.Add(startNewLink);
                    dlg.Controls.Add(continuteLink);

                    dlg.Show();
                }
            }
            else
            {
                var result = MessageBox.Show("Start New Game?", "Start New Game", MessageBoxButton.YesNo, MessageBoxImage.Question);
                if (result == MessageBoxResult.Yes)
                    startNew = true;
            }

            if (startNew)
            {
                new NewGameDialog().Show();
                Close();
            }
        }

        void ReturnMenuItemHandler(object sender, RoutedEventArgs e)
        {
            bool doReturn = false;

            if (TaskDialog.IsPlatformSupported)
            {
                using (var dlg = new TaskDialog())
                {
                    dlg.Caption = "Abort Current Game";
                    dlg.InstructionText = "Return to Start Screen?";
                    dlg.Text = "Do you want to abort the current game (losing all progress) and return to the Start Screen?";
                    dlg.OwnerWindowHandle = this.Handle;
                    dlg.StartupLocation = TaskDialogStartupLocation.CenterOwner;

                    var startNewLink = new TaskDialogCommandLink("return", "Abort Game");
                    var continuteLink = new TaskDialogCommandLink("continue", "Continue", "Continue with current game.");

                    startNewLink.Click += delegate
                    {
                        doReturn = true;
                        dlg.Close();
                    };
                    continuteLink.Click += delegate
                    {
                        dlg.Close();
                    };

                    dlg.Controls.Add(startNewLink);
                    dlg.Controls.Add(continuteLink);

                    dlg.Show();
                }
            }
            else
            {
                var result = MessageBox.Show("Abort current game and return to Start Window?", "Abort current game?", MessageBoxButton.YesNo, MessageBoxImage.Question);
                if (result == MessageBoxResult.Yes)
                    doReturn = true;
            }

            if (doReturn)
            {
                new StartWindow().Show();
                Close();
            }
        }

        void TurnWindowClosing(object sender, CancelEventArgs e)
        {
            _game.OnTurn -= _turnWindow.TurnHandler;
            _turnWindowOpened = false;
        }

        void ChatWindowClosing(object sender, CancelEventArgs e)
        {
            _chatWindow.MessageReady -= (_game as NetGame).SendChatMessage;
            (_game as NetGame).OnChatMessageReceived -= _chatWindow.ChatMessageReceived;
            _chatWindowOpened = false;
        }

        void ToggleTurnWindow(object sender, RoutedEventArgs e)
        {
            if (_turnWindowOpened)
                _turnWindow.Close();
            else
            {
                _turnWindow = new TurnListWindow(_game.Turns);
                _turnWindow.Closing += TurnWindowClosing;
                _game.OnTurn += _turnWindow.TurnHandler;
                _turnWindow.Show();
                _turnWindowOpened = true;
            }
        }

        void ToggleChatWindow(object sender, RoutedEventArgs e)
        {
            if (!_isNetGame)
                throw new InvalidOperationException("Can't chat in local game");

            if (_chatWindowOpened)
                _chatWindow.Close();
            else
            {
                _chatWindow = new NetChatWindow((_game as NetGame).LocalPlayer, (_game as NetGame).RemotePlayer);
                _chatWindow.MessageReady += (_game as NetGame).SendChatMessage;
                _chatWindow.Closing += ChatWindowClosing;
                (_game as NetGame).OnChatMessageReceived += _chatWindow.ChatMessageReceived;
                _chatWindow.Show();
                _chatWindowOpened = true;
            }
        }

        void WindowClosing(object sender, CancelEventArgs e)
        {
            if (_chatWindowOpened)
                _chatWindow.Close();

            if (_turnWindowOpened)
                _turnWindow.Close();
        }

        void ResetRotation(object sender, RoutedEventArgs e)
        {
            gameView3D.ResetCameraRotation();
        }

        void ResetZoom(object sender, RoutedEventArgs e)
        {
            gameView3D.ResetCameraZoom();
        }

        #endregion
    }
}
